package com.chx.three.mama.utils;

import android.content.Context;
import android.os.Environment;

import java.io.*;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Date;

/**
 * Created by Casio on 2015/2/6.
 */
public class FileCache {
    private static FileCache ourInstance;

    /**
     * 这个方法必须在getInstance之前调用，主要用于初始化Android中特有的Context和应用程序私有缓存目录的功能。
     * @param context
     * @return
     */
    public static FileCache createInstance(Context context){
        if (ourInstance == null) {
            ourInstance = new FileCache(context);
        }
        return ourInstance;
    }

    public static FileCache getInstance() {
        if (ourInstance==null){
            throw new IllegalStateException("FileCache must invoke createInstance() before getInstance().");
        }
        return ourInstance;
    }

    //Android上下文Context
    private Context context;
    //当前文件缓存的目录，主要针对网址上的资源，下载到本地的情况
    private File fileCacheDir;

    /**
     * 在私有构造方法中指定参数，那么这个构造方法必须由当前类进行初始化，
     * 那么必须在静态方法中调用。
     */
    private FileCache(Context context) {
        this.context=context;
        if (context!=null){

            String state = Environment.getExternalStorageState();
            if (Environment.MEDIA_MOUNTED.equals(state)){
                fileCacheDir = context.getExternalCacheDir();
            }else {
                fileCacheDir=context.getCacheDir();
            }
        }else {
            String state = Environment.getExternalStorageState();
            if (Environment.MEDIA_MOUNTED.equals(state)){
                File directory = Environment.getExternalStorageDirectory();
                fileCacheDir=new File(directory,".youshare");
            }else {
                throw new IllegalArgumentException("FileCache must set context or device has a sdcard.");
            }

        }
        if (fileCacheDir!=null){
            if (!fileCacheDir.exists()){
                fileCacheDir.mkdirs();
            }
        }else {
            throw new IllegalArgumentException("FileCache can't get a cache dir.");
        }

    }

    /**
     * 将下载的内容根据 url映射规则，保存到相应的文件中
     * @param url
     * @param data
     */
    public void putContent(String url,byte[] data){
        if (url!=null && data!=null){
            String fileName = mapUrlToFile(url);
            File targetFile = new File(fileCacheDir, fileName);

            boolean bok=true;
            if (!targetFile.exists()){
                try {
                    bok=targetFile.createNewFile();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }


            if (bok){
                FileOutputStream fout=null;
                try {
                    fout=new FileOutputStream(targetFile);
                    fout.write(data);
                } catch (FileNotFoundException e) {
                    e.printStackTrace();
                } catch (IOException e) {
                    e.printStackTrace();
                }finally {
                    StreamUtil.close(fout);
                }

            }
        }
    }

    /**
     * 获取url代表的数据，从本地存储中，如果有本地文件，那么返回有效，否则返回null
     * @param url
     * @return
     */
    public byte[] getContent(String url){

        byte[] ret = null;
        if (url!=null){
            //url中通常存在不能作为文件名的字符，这种情况需要进行映射。url唯一地转换成文件名字符串    MD5  消息摘要算法。

            String fileName = mapUrlToFile(url);
            if (fileName.length()>0){

                File targetFile = new File(fileCacheDir, fileName);
                if (targetFile.exists()){

                    FileInputStream fin=null;
                    try {
                        fin=new FileInputStream(targetFile);
                        ret=StreamUtil.readStream(fin);
                    } catch (FileNotFoundException e) {
                        e.printStackTrace();
                    } catch (IOException e) {
                        e.printStackTrace();
                    } finally {
                        StreamUtil.close(fin);
                        fin=null;
                    }
                }
            }
        }
        return ret;
    }

    /**
     * url---> 文件名
     * @param url
     * @return
     */

    private static String mapUrlToFile(String url){
        String ret = null;

        if (url!=null){
            //MD5将任何内容转换为不可逆的，唯一的，一个字节数组

            byte[] md5 = md5(url.getBytes());
            ret=hex(md5);

        }
        return ret;

    }

    /**
     * MD5算法
     * @param data
     * @return
     */
    private static byte[] md5(byte[] data){

        byte[] ret = null;
        if (data!=null && data.length>0){

            try {
                MessageDigest digest=MessageDigest.getInstance("MD5");
                ret=digest.digest(data);//将data进行消息摘要，生成一个特定的字节数组，当中的数值不可逆转

            } catch (NoSuchAlgorithmException e) {
                e.printStackTrace();
            }
        }
        return ret;

    }

    /**
     * 将字节数组中的每一个字节转换成0--9，A---F，这些可以显示的十六进制表示法的字符
     * @param data
     * @return
     */
    private static String hex(byte[] data){

        StringBuilder sb = new StringBuilder();
        if (data!=null && data.length>0){

            for (byte b:data){

                int h,l;
                h=(b>>4)&0x0f;
                l=b&0x0f;

                sb.append(Integer.toHexString(h));
                sb.append(Integer.toHexString(l));
            }
        }
        return sb.toString();
    }


}
